package com.map.brush;

import com.map.shader.ShaderHelper;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_POINTS;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttrib1f;
import static android.opengl.GLES20.glVertexAttribPointer;
import static com.map.brush.Constants.BYTES_PER_FLOAT;
import static com.map.brush.Constants.COLOR_COMPONENT_COUNT;
import static com.map.brush.Constants.POSITION_COMPONENT_COUNT;
import static com.map.brush.Constants.SIZE_COMPONENT_COUNT;

public class PointBrush extends Brush {
    private static final String A_POSITION = "a_Position";
    private static final String A_COLOR = "a_Color";
    private static final String A_SIZE = "a_PointSize";
    private static final String U_MATRIX = "u_Matrix";
    private static final int STRIDE =
            (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT + SIZE_COMPONENT_COUNT) * BYTES_PER_FLOAT;

    private final FloatBuffer vertexData;

    private int program;
    private int aPositionLocation;
    private int aColorLocation;
    private int aSizeLocation;
    private int uMatrixLocation;
    private float pointSize = 0f;
    private int pointCounts;//点的数量

    private boolean  hasCompiled=false;

    /**
     * x+y+r+g+b+pointSize进行绘制
     *
     * @param data 数据
     */
    public PointBrush(float[] data) {
        pointCounts = data.length / 6;
        vertexData = ByteBuffer
                .allocateDirect(data.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        vertexData.put(data);
    }

    /**
     * 统一点大小进行绘制
     *
     * @param data      数据
     * @param pointSize 点大小
     */
    public PointBrush(float[] data, float pointSize) {
        pointCounts = data.length / 5;
        vertexData = ByteBuffer
                .allocateDirect(data.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        vertexData.put(data);
        this.pointSize = pointSize;
    }


    /**
     * 进行绘制
     */
    @Override
    public void draw(float[] matrix) {
        //如果未编译则进行编译
        if(!hasCompiled){
            compile();
        }

        //设置投影
        glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);
        glDrawArrays(GL_POINTS, 0, pointCounts);
    }

    /**
     * 对OpenGL ES资源进行编译
      */
    private void compile(){
        int vertexShader = ShaderHelper.compileVertexShader(ShaderCode.VERTEX);
        int fragmentShader = ShaderHelper
                .compileFragmentShader(ShaderCode.FRAGMENT);

        program = ShaderHelper.linkProgram(vertexShader, fragmentShader);
        glUseProgram(program);

        aPositionLocation = glGetAttribLocation(program, A_POSITION);
        aColorLocation = glGetAttribLocation(program, A_COLOR);
        aSizeLocation = glGetAttribLocation(program, A_SIZE);
        uMatrixLocation = glGetUniformLocation(program, U_MATRIX);
        vertexData.position(0);
        glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        glEnableVertexAttribArray(aPositionLocation);


        vertexData.position(POSITION_COMPONENT_COUNT);
        glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        glEnableVertexAttribArray(aColorLocation);


        if (pointSize == 0f) {
            vertexData.position(POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT);
            glVertexAttribPointer(aSizeLocation, SIZE_COMPONENT_COUNT, GL_FLOAT,
                    false, STRIDE, vertexData);
            glEnableVertexAttribArray(aSizeLocation);//使用缓冲区赋值
        } else {
            glVertexAttrib1f(aSizeLocation, pointSize);//统一赋值点大小
        }

        hasCompiled=true;
    }

    /**
     * 回收占用GPU资源
     */
    @Override
    public void destroy() {

    }

    /**
     * 着色器代码
     */
    private static class ShaderCode {
        final static String VERTEX =
                "uniform mat4 u_Matrix;" +

                        "attribute vec4 a_Position;" +
                        "attribute vec4 a_Color;" +
                        "attribute float a_PointSize;" +

                        "varying vec4 v_Color;" +

                        "void main()" +
                        "{" +
                        "    gl_Position =  u_Matrix * a_Position;" +
                        "    gl_PointSize = a_PointSize;" +
                        "    v_Color = a_Color;" +
                        "}";
        final static String FRAGMENT =
                "precision mediump float;" +
                        "varying vec4 v_Color;" +
                        "void main()" +
                        "{" +
                        "  float d = distance(gl_PointCoord, vec2(0.5, 0.5));" +
                        "  if(d < 0.5) " +
                        "   {gl_FragColor = v_Color;} " +
                        "  else { discard; }" +
                        "}";
    }
}
